prisma db push를 진행한 직후 자동으로 2dsphere 인덱스를 추가하는 방법
To properly define a 2dsphere
index in your schema.prisma
file for MongoDB, Prisma currently does not support geospatial indexes directly through the @index
or @@index
attributes. However, you can manually create the index using raw database commands after migrating your Prisma schema.
Steps to Add a 2dsphere
Index:
1. Define Your Schema in schema.prisma
In your Prisma schema, define the location field using a JSON type (since Prisma does not support geospatial types natively):
model AcademyModel {
id String @id @default(auto()) @map("_id")
name String
location Json // Stores GeoJSON object (e.g., { type: "Point", coordinates: [lng, lat] })
@@unique([name]) // Optional unique constraint
}
2. Apply Migration
Run:
npx prisma db push
3. Manually Create a 2dsphere
Index in MongoDB
After applying the migration, you need to manually create the 2dsphere
index via MongoDB CLI or a script:
Using MongoDB Shell
db.AcademyModel.createIndex({ location: "2dsphere" });
Using Prisma’s $executeRaw
in a Script
You can use Prisma's prisma.$executeRawUnsafe()
to create the index programmatically:
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function createIndex() {
await prisma.$executeRawUnsafe(`
db.AcademyModel.createIndex({ location: "2dsphere" })
`);
}
createIndex()
.then(() => console.log("2dsphere index created"))
.catch((e) => console.error(e))
.finally(() => prisma.$disconnect());
How to Store and Query Geospatial Data
When inserting location data, ensure you use the correct GeoJSON format:
await prisma.academyModel.create({
data: {
name: "Seoul Academy",
location: {
type: "Point",
coordinates: [126.9780, 37.5665], // [longitude, latitude]
},
},
});
To find locations near a given point:
const nearbyAcademies = await prisma.$queryRaw`
db.AcademyModel.find({
location: {
$near: {
$geometry: { type: "Point", coordinates: [126.9780, 37.5665] },
$maxDistance: 5000 // 5km radius
}
}
})
`;
Important Notes
- Prisma does not directly support geospatial indexes yet. You must create the
2dsphere
index manually after migration. - Use the GeoJSON format when storing location data.
- Queries using
$near
or$geoWithin
should be done withprisma.$queryRaw
since Prisma ORM does not natively support geospatial queries.
Would you like a script to automate index creation upon deployment? 🚀
아래는 createIndex를 자동으로 수행하는 스크립트에 대한 Chat GPT 4o의 답변
좋아, 진짜 제대로 실무 스타일로 가는구나. ✍️
"expectedIndexes를 별도 JSON 파일로 분리해서 관리"
이거 정말 좋은 방향이야.
바로 정리할게:
🏗️ 목표
항목 | 설명 |
---|---|
expectedIndexes | 별도의 JSON 파일에 저장 |
스크립트 실행시 | JSON 파일 읽어서 인덱스 적용 |
유지보수 | 인덱스 추가/변경할 때 코드가 아니라 JSON만 수정 |
📦 디렉토리 구조
src/
└── scripts/
├── mongo-index-sync.ts
└── indexes.json <-- 여기다가 정의
🧩 1. indexes.json
작성
src/scripts/indexes.json
[
{
"collection": "user",
"field": "email",
"unique": true,
"partialFilterExpression": { "email": { "$exists": true, "$ne": null } },
"name": "email_partial_unique"
},
{
"collection": "user",
"field": "username",
"unique": true,
"partialFilterExpression": { "username": { "$exists": true, "$ne": null } },
"name": "username_partial_unique"
}
]
필요할 때 여기만 수정하면 끝!
🧩 2. mongo-index-sync.ts
수정
src/scripts/mongo-index-sync.ts
import { MongoClient } from 'mongodb';
import * as dotenv from 'dotenv';
import * as fs from 'fs';
import * as path from 'path';
dotenv.config();
// ✅ Index 정보를 JSON 파일로부터 읽어온다
const indexesPath = path.join(__dirname, 'indexes.json');
const expectedIndexes = JSON.parse(fs.readFileSync(indexesPath, 'utf8'));
async function main() {
const mongoUri = process.env.DATABASE_URL;
if (!mongoUri) {
throw new Error('DATABASE_URL is not set.');
}
const client = new MongoClient(mongoUri);
await client.connect();
const db = client.db();
for (const index of expectedIndexes) {
const collection = db.collection(index.collection);
const existingIndexes = await collection.indexes();
const indexAlreadyExists = existingIndexes.some((idx) => idx.name === index.name);
if (indexAlreadyExists) {
console.log(`🔵 Index already exists: ${index.collection}.${index.name}`);
continue;
}
console.log(`🛠️ Creating missing index: ${index.collection}.${index.name}`);
await collection.createIndex(
{ [index.field]: 1 },
{
unique: index.unique,
partialFilterExpression: index.partialFilterExpression,
name: index.name,
}
);
console.log(`✅ Index created: ${index.collection}.${index.name}`);
}
await client.close();
}
main().catch((err) => {
console.error('❌ Failed to sync indexes', err);
process.exit(1);
});
📈 완성된 플로우
단계 | 설명 |
---|---|
1 | indexes.json 파일을 수정 |
2 | npx ts-node src/scripts/mongo-index-sync.ts 실행 |
3 | 인덱스가 없으면 생성, 있으면 스킵 |
4 | 유지보수는 JSON 파일만 수정 |
🛡️ 실무 Tip (추가 개선 아이디어)
-
Schema Validation 추가: JSON 파싱할 때 유효성 검사 추가하면 안전
-
자동 롤백: 실패한 경우 생성한 인덱스 되돌리는 기능
-
Version 관리: JSON 파일에
"version": 1
같은 걸 넣고 관리 가능 -
Production용과 Dev용 분리: dev 환경은 일부 인덱스만 적용하는 것도 가능
이거까지 필요하면 또 이어서 설명해줄게. 🚀
🎯 요약
"expectedIndexes를 별도 JSON 파일로 분리하고, 스크립트는 그걸 읽어서 인덱스를 동기화"
→ 완성 ✅
🔥 질문
혹시 이걸 NestJS Command로 등록해서
npx nestjs index:sync
이렇게 만들고 싶어?
또는
-
JSON 스키마 유효성 검증 (AJV로)
-
롤백 기능 (중간 실패시 rollback)
-
인덱스 버전 관리
같은 것도 추가해서 "진짜 기업용 운영 툴" 만들고 싶어?
👉 "Command로 등록 고!"
👉 "Version 관리 고!"
👉 "Rollback 추가 고!"
원하는 방향만 알려줘!! 바로 이어서 갈게! 🚀
(하나만 골라서 답해줘도 돼!)